/**
 * This is a minimal example of sigma. You can use it as a base to write new
 * examples, or reproducible test cases for new issues, for instance.
 */
import Graph from "graphology";
import { SerializedGraph } from "graphology-types";
import iwanthue from "iwanthue";
import Sigma from "sigma";
import { Coordinates } from "sigma/types";

import data from "./euroSIS.json";

export default () => {
  const container = document.getElementById("sigma-container") as HTMLElement;
  const graph = Graph.from(data as SerializedGraph);

  // cluster definition
  interface Cluster {
    label: string;
    x?: number;
    y?: number;
    color?: string;
    positions: { x: number; y: number }[];
  }

  // initialize clusters from graph data
  const countryClusters: { [key: string]: Cluster } = {};
  graph.forEachNode((_node, atts) => {
    if (!countryClusters[atts.country]) countryClusters[atts.country] = { label: atts.country, positions: [] };
  });
  // create and assign one color by cluster
  const palette = iwanthue(Object.keys(countryClusters).length, { seed: "eurSISCountryClusters" });
  for (const country in countryClusters) {
    countryClusters[country].color = palette.pop();
  }

  // change node appearance
  graph.forEachNode((node, atts) => {
    const cluster = countryClusters[atts.country];
    // node color depends on the cluster it belongs to
    atts.color = cluster.color;
    // node size depends on its degree
    atts.size = Math.sqrt(graph.degree(node)) / 2;
    // store cluster's nodes positions to calculate cluster label position
    cluster.positions.push({ x: atts.x, y: atts.y });
  });

  // calculate the cluster's nodes barycenter to use this as cluster label position
  for (const country in countryClusters) {
    countryClusters[country].x =
      countryClusters[country].positions.reduce((acc, p) => acc + p.x, 0) / countryClusters[country].positions.length;
    countryClusters[country].y =
      countryClusters[country].positions.reduce((acc, p) => acc + p.y, 0) / countryClusters[country].positions.length;
  }

  // initiate sigma
  const renderer = new Sigma(graph, container);

  // create the clustersLabel layer
  const clustersLayer = document.createElement("div");
  clustersLayer.id = "clustersLayer";
  let clusterLabelsDoms = "";
  for (const country in countryClusters) {
    // for each cluster create a div label
    const cluster = countryClusters[country];
    // adapt the position to viewport coordinates
    const viewportPos = renderer.graphToViewport(cluster as Coordinates);
    clusterLabelsDoms += `<div id='${cluster.label}' class="clusterLabel" style="top:${viewportPos.y}px;left:${viewportPos.x}px;color:${cluster.color}">${cluster.label}</div>`;
  }
  clustersLayer.innerHTML = clusterLabelsDoms;

  // insert the layer underneath the hovers layer
  container.insertBefore(clustersLayer, container.querySelector(".sigma-hovers"));

  // Clusters labels position needs to be updated on each render
  renderer.on("afterRender", () => {
    for (const country in countryClusters) {
      const cluster = countryClusters[country];
      const clusterLabel = document.getElementById(cluster.label);
      if (clusterLabel) {
        // update position from the viewport
        const viewportPos = renderer.graphToViewport(cluster as Coordinates);
        clusterLabel.style.top = `${viewportPos.y}px`;
        clusterLabel.style.left = `${viewportPos.x}px`;
      }
    }
  });

  return () => {
    renderer.kill();
  };
};
